home *** CD-ROM | disk | FTP | other *** search
- /*++
- /* NAME
- /* kbdinp 3
- /* SUMMARY
- /* keyboard interpreter
- /* PROJECT
- /* pc-mail
- /* PACKAGE
- /* mail
- /* SYNOPSIS
- /* void kbdinp(screen)
- /* Screen *screen;
- /*
- /* void kbdinit()
- /*
- /* void kbdrest()
- /*
- /* int getkey()
- /* DESCRIPTION
- /* The keyboard interpreter is the machine that executes the program
- /* that is recorded in the form of Screen data structures.
- /* Its task is to interpret keyboard input and to
- /* invoke the appropriate action functions.
- /*
- /* Depending on the return value of an action function
- /* the keyboard interpreter i) returns (S_BREAK), ii) repaints the
- /* screen (S_REDRAW), or iii) just waits for more keyboard
- /* input. Error handling is entirely up to the action functions.
- /*
- /* The routines in this module are responsible for what appears in the
- /* top (function-key labels) and bottom sections (command dialogue)
- /* of the tty screen.
- /*
- /* The middle screen section is handled by the pager (except when
- /* help info is displayed).
- /*
- /* kbdinit() sets the tty driver and keypad modes (no echo,
- /* punctual input).
- /*
- /* kbrest() restores the modes to what they were when kbdinit() was
- /* invoked.
- /*
- /* getkey() returns the next keypress (see screen.h for function-key
- /* codes) and maps lower case to upper case.
- /*
- /* Terminal-specific codes for function keys and keypad are borrowed
- /* from window.c.
- /* FUNCTIONS AND MACROS
- /* printcl(), printat(), wputc(), wputs(), beep(), winout()
- /* SEE ALSO
- /* window(3) window management routines, function key codes
- /* window(5) window definitions
- /* screen(3) command key tables for each screen
- /* screen(5) structure of command key tables
- /* DIAGNOSTICS
- /* It beeps when an illegal key is pressed. Otherwise, no error
- /* handling at all.
- /* AUTHOR(S)
- /* W.Z. Venema
- /* Eindhoven University of Technology
- /* Department of Mathematics and Computer Science
- /* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
- /* CREATION DATE
- /* Thu Apr 2 18:43:12 GMT+1:00 1987
- /* LAST MODIFICATION
- /* 90/01/22 13:01:51
- /* VERSION/RELEASE
- /* 2.1
- /*--*/
-
- #include <stdio.h>
- #include <signal.h>
- #include <ctype.h>
-
- #include "defs.h"
- #include "mail.h"
- #include "screen.h"
- #include "window.h"
-
- #ifdef unix
- #if (SIII||SYSV) /* AT&T */
- #include <termio.h>
- struct termio oldmode;
- #else /* V7 or Berkeley */
- #include <sgtty.h>
- struct sgttyb oldmode;
- # endif
- #endif
-
- /* How to generate a brief delay when the user presses ESC */
-
- #ifdef MSDOS
- #define sleep(x) { unsigned i; for (i = 1; i > 0; i++) ; }
- #endif
-
- /* Forward declarations */
-
- hidden void kb_help(); /* Display context-sensitive help */
- hidden void kb_pause(); /* Press any key to continue */
- hidden int kb_paint(); /* Screen update routine */
- hidden int kb_str(); /* Read an arbitrary string */
- hidden int kb_key(); /* Read single-key input */
- hidden int kb_cr(); /* Allow ESC or ENTER as input */
- hidden int kb_edt(); /* String input with default */
- hidden int kb_yn(); /* Yes/no input */
- hidden char *kb_read(); /* Basic input function */
- hidden int input(); /* Read one key stroke */
- hidden int isempty(); /* String is all blanks */
-
- /* Various strings */
-
- #define QUEST "? " /* prompt for input */
- hidden char sect[] = "=========================================================\
- ======================";
-
- /* The maximal length of string input; depends on the window size */
-
- hidden int maxstr;
-
- /* kbdinp - recursively interpret screen descriptions */
-
- public int kbdinp(screen)
- Screen *screen;
- {
- kb_paint(screen);
-
- if (iskey(screen->key))
- return (kb_key(screen)); /* single-key commands */
- else if (screen->key == STRING)
- return (kb_str(screen)); /* string input screen */
- else if (screen->key == EDIT)
- return (kb_edt(screen)); /* string edit screen */
- else if (screen->key == YESNO)
- return (kb_yn(screen)); /* yes/no screen */
- else if (screen->key == ESCCR)
- return (kb_cr(screen)); /* confirm/cancel screen */
- else
- fatal("kbdinp"); /* unexpected screen type */
- /* NOTREACHED */
- }
-
- /* kb_paint - paint the screen (clean up this function) */
-
- hidden int kb_paint(p)
- register Screen *p;
- {
- char topline[BUFSIZ]; /* key label line */
- register int k; /* loop control variable */
- int stat = 0; /* status from mid window */
- int promptloc; /* where prompt "?" goes */
-
- /*
- * The top section of the screen consists of one line with key labels (in
- * case of single-key input screen) and a bar that separates this section
- * from the middle screen section.
- *
- * We always add a Help and ? label. Thus, the interpreter preempts the
- * use of the H and ? characters.
- */
-
- for (topline[0] = 0; p->key; p++) { /* start top window */
- if (iskey(p->key)) { /* keystroke input ? */
- strcat(topline, p->name); /* append key label */
- strcat(topline, " "); /* and some blanks */
- } else if (topline[0]) { /* leak if first entry */
- fatal("mixed single-key and string input");
- }
- }
- printcl(topwin, 0, topline); /* display key labels */
- if (topline[0]) /* if there are labels */
- wputs("Help ?"); /* display help key labels */
- printcl(topwin, 1, sect); /* finish top window with bar */
-
- /*
- * The bottom section of the screen consists of a bar that separates us
- * from the middle section, followed by the "help" string in the last
- * entry of the current screen definition, followed by (if not a
- * single-key input screen) a prompting question mark.
- */
-
- printcl(botwin, 0, sect); /* start lower window */
- promptloc = printcl(botwin, 1, p->help ? p->help : "") + 1;
- for (k = promptloc; k < botwin->size; k++) /* clear rest of lower window */
- printcl(botwin, k, ""); /* lower window done */
-
- if (p->action) /* fill middle window */
- stat = CALL(p->action) (); /* middle window done */
-
- /*
- * We leave the focus on the middle window, in case of single-key input,
- * and move the focus to the bottom window in case of prompted input.
- */
-
- if (topline[0] == 0) /* prompted input screen? */
- printat(botwin, promptloc, QUEST); /* output "?" prompt */
-
- /* Determine maximal length of string input */
-
- maxstr = MAX(((botwin->size - 1) * CO - sizeof(QUEST) - 2), BUFSIZ - 1);
-
- return (stat); /* from middle window filler */
- }
-
- /* kb_str - handle string input without defaults */
-
- hidden int kb_str(p)
- register Screen *p;
- {
- char string[BUFSIZ]; /* a character buffer */
- register int stat;
-
- for (;;) {
- string[0] = '\0'; /* no default input */
- if (kb_read(string) == 0) { /* command cancelled? */
- return (0); /* quit */
- } else if ((stat = CALL(p->action) (string)) & S_BREAK) {
- return (stat); /* we're done here */
- } else if (stat & S_REDRAW) { /* screen was changed */
- kb_paint(p); /* restore display */
- }
- }
- }
-
- /* kb_yn - handle yes/no input */
-
- hidden int kb_yn(p)
- register Screen *p;
- {
- char string[BUFSIZ]; /* a character buffer */
- register int stat; /* return status */
- static char yn[] = "nNyY"; /* input is not mapped to upper case */
- char *in;
-
- for (string[0] = '\0';;) { /* clear input */
- if (kb_read(string) == 0) { /* command cancelled? */
- return (0); /* quit */
- } else if ((in = index(yn, string[0])) == 0) { /* validate */
- beep(); /* complain */
- kb_paint(p); /* restore display */
- } else if ((stat = CALL(p->action) (in - yn > 1)) & S_BREAK) {
- return (stat); /* we're done here */
- } else if (stat & S_REDRAW) { /* screen was changed */
- kb_paint(p); /* restore display */
- string[0] = '\0'; /* clear input */
- }
- }
- }
-
- /* kb_edt - handle string input with default */
-
- hidden int kb_edt(p)
- register Screen *p;
- {
- char string[BUFSIZ]; /* user input */
- register int stat; /* return status */
-
- for (;;) {
- (void) strncpy(string, p->help, BUFSIZ);/* stuff default input */
- if (kb_read(string) == 0) { /* command cancelled */
- return (0); /* quit */
- } else if ((stat = CALL(p->action) (string)) & S_BREAK) {
- return (stat); /* we're done here */
- } else if (stat & S_REDRAW) { /* screen was changed */
- kb_paint(p); /* restore display */
- }
- }
- }
-
- /* kb_read - general string edit/input routine */
-
- hidden char *kb_read(string)
- char string[BUFSIZ];
- {
- register char *cp; /* a character pointer */
- register int c; /* a character */
-
- cp = string + strlen(string); /* update buffer pointer */
- wputs(string); /* show input to be edited */
-
- for (;;) {
- if (!isascii(c = input())) { /* ignore non-ascii codes */
- beep(); /* complain */
- } else if (c == ESC) { /* ESC means don't do it */
- wputs(" (ESC)"); /* confirm input */
- sleep(1);
- return (0); /* nothing left here to do */
- } else if (c == ENTER && (*cp = 0, !isempty(string))) {
- wputc(c); /* echo */
- return (string); /* we're done here */
- } else if (c == BS || c == DEL) {
- if (cp > string)
- cp--, wputs("\b \b"); /* remove one character */
- } else if (c == CTLU) { /* line erase */
- while (cp > string)
- cp--, wputs("\b \b");
- } else if ((c == ' ' || isprint(c)) && (cp - string) < maxstr) {
- wputc(*cp++ = c); /* accept and echo */
- } else {
- beep(); /* complain */
- }
- }
- }
-
- /* kb_key - handle single-key input */
-
- hidden int kb_key(p)
- Screen *p;
- {
- register int c; /* a character */
- register Screen *q; /* a screen (eh?) */
- register int stat; /* a status */
-
- for (;;) {
- if ((c = getkey()) == '?' || c == 'H') {/* is it a help request */
- kb_help(p); /* yes, display key info */
- continue; /* skip rest of loop */
- }
- for (q = p; q->key && q->key != c; q++) /* look key up in table */
- /* void */
- ;
- if (q->key == 0) { /* unrecognized key */
- beep(); /* complain */
- } else if (q->action == 0) { /* action-less key */
- return (0); /* we are done here */
- } else if ((stat = CALL(q->action) ()) & S_BREAK) { /* do action */
- return (stat); /* we are done here */
- } else if (stat & S_REDRAW) { /* screen was changed */
- kb_paint(p); /* restore screen */
- }
- }
- }
-
- /* kb_cr - handle escape/enter input */
-
- hidden int kb_cr(p)
- Screen *p;
- {
- register int c;
- register int stat;
-
- for (;;) {
- if ((c = input()) == ESC) { /* don't do it */
- wputs(" (ESC)"); /* confirm input */
- sleep(1);
- return (0); /* we are done */
- } else if (c == ENTER) { /* do the action */
- stat = CALL(p->action) (); /* execute action */
- if (stat & S_BREAK) { /* child kills parent */
- return (stat); /* we are done */
- } else if (stat & S_REDRAW) { /* screen was changed */
- kb_paint(p); /* restore screen */
- }
- } else { /* unacceptable input */
- beep(); /* complain */
- }
- }
- }
-
- /* kb_help - display per-key help info; redraw screen when done */
-
- hidden void kb_help(p)
- register Screen *p;
- {
- register int k;
-
- for (k = 0; k < midwin->size; k++) /* erase middle window */
- printcl(midwin, k, "");
- for (k = 0; p[k].key; k++) /* display key info */
- printcl(midwin, k + 1, strcons(" %-10s %s", isascii(p[k].key) &&
- isprint(p[k].key) ? p[k].name[1] ? strcons("%c(%s)", p[k].key,
- p[k].name + 1) : strcons("%c", p[k].key) : p[k].name, p[k].help));
- for (k = 1; k < botwin->size - 1; k++) /* erase bottom window */
- printcl(botwin, k, "");
- printcl(botwin, 1, anykey); /* press any key to continue */
- getkey();
- kb_paint(p); /* redraw screen */
- }
-
- /* structure that associates token value with function-key strings */
-
- struct keydef {
- char **strval; /* key string */
- int tokval; /* key value */
- };
-
- hidden struct keydef keys[] = {
- &KU, UP, /* key strings are set */
- &KD, DOWN, /* in window.c */
- &KL, LEFT,
- &KR, RIGHT,
- &PU, PGUP,
- &PD, PGDN,
- 0, 0,
- };
-
- /* getkey - get key stroke, detect function keys, ignore case otherwise */
-
- public int getkey()
- {
- register int c;
- register struct keydef *kp;
- char kstr[BUFSIZ];
- register int len;
-
- /*
- * We assume that all function keys produce strings that start with the
- * same lead-in character, and that those strings all have the same
- * length. This is a reasonable assumption for cursor-control keys on
- * most terminals.
- */
-
- if ((c = input()) == **(keys->strval)) { /* lead-in character */
-
- /*
- * Read a number of characters equal to the length of the strings
- * generated by function keys.
- */
-
- for (len = 1; len < strlen(*(keys[0].strval)); len++)
- kstr[len] = c = input();
- kstr[len] = '\0';
-
- /* Compare what we just read with known function-key strings. */
-
- for (kp = keys; kp->tokval; kp++)
- if (strcmp(*(kp->strval) + 1, kstr + 1) == 0)
- return (kp->tokval); /* return token value */
- }
- /* Return the last read character. */
-
- return ((isascii(c) && islower(c)) ? toupper(c) : c);
- }
-
- /* input - read one character without echoing or waiting for carriage return */
-
- hidden int input()
- {
-
- #ifdef unix
-
- /*
- * On unix systems, the terminal driver has been instructed to not echo
- * and to return one character as soon as it comes available. Also the
- * stdio routines have been instructed to process input in an unbuffered
- * fashion. See kbdinit().
- */
-
- return (getchar());
- #endif
-
- #ifdef MSDOS
-
- /*
- * On IBM-PC machines a function key produces a null character followed
- * by a scan code. We translate the null prefix to an escape character
- * since that is more like normal terminals do. The trick is to find out
- * when we read a null character whether it was produced by pressing a
- * real function-key or by pressing ctrl-@.
- */
-
- register int c;
-
- return ((c = getch()) ? c : kbhit() ? ESC : 0);
- #endif
-
- #if (!defined(unix) && !defined(MSDOS))
- "You should either define unix or MSDOS, or add support for another OS"
- #endif
- }
-
- /* kbdinit - set input mode, turn keypad on */
-
- public void kbdinit()
- {
-
- #ifdef MSDOS
- (void) signal(SIGINT, SIG_IGN); /* ignore control-c */
- #endif
-
- #ifdef unix
-
- /*
- * On unix systems, instruct the terminal driver to not echo terminal
- * input, and to return from a read as soon as one character comes
- * available.
- */
-
- # if (SIII||SYSV)
- struct termio newmode; /* AT&T */
-
- (void) ioctl(0, TCGETA, &oldmode); /* save terminal mode */
- (void) ioctl(0, TCGETA, &newmode); /* get terminal mode */
- newmode.c_iflag &= ~(ICRNL | BRKINT);
- newmode.c_oflag &= ~OPOST;
- newmode.c_lflag &= ~(ICANON | ISIG | ECHO);
- newmode.c_cc[VMIN] = 1;
- newmode.c_cc[VTIME] = 0;
- (void) ioctl(0, TCSETAF, &newmode); /* set terminal mode */
- # else
- struct sgttyb newmode; /* V7 or Berkeley */
-
- (void) gtty(0, &oldmode); /* save terminal mode */
- (void) gtty(0, &newmode); /* get terminal mode */
- newmode.sg_flags |= RAW;
- newmode.sg_flags &= ~(ECHO | CRMOD);
- (void) stty(0, &newmode); /* set terminal mode */
- # endif
-
- setbuf(stdin, (char *) 0); /* select unbuffered input */
-
- if (KS && *KS) /* if there is a keypad */
- tputs(KS, 1, fputchar); /* enable it */
- #endif
- }
-
- /* kbdrest - reset terminal driver to previous state, turn keypad off */
-
- public void kbdrest()
- {
- #ifdef unix
-
- /* Restore tty modes, either the AT&T way or the BSD+V7 way */
-
- # if (SIII||SYSV)
- ioctl(0, TCSETAF, &oldmode);
- # else
- stty(0, &oldmode);
- # endif
-
- /* Disable keypad if there is one */
-
- if (KE && *KE)
- tputs(KE, 1, fputchar);
- #endif
- }
-
- /* isempty - check a string is all blanks or empty */
-
- hidden int isempty(s)
- register char *s;
- {
- while (*s && isspace(*s))
- s++;
- return (*s == 0);
- }
-